import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
import * as logger from '../logger';
/**
 * 节点遍历，使用 callback 进行处理
 */
export var forEach = function forEach(treeNodes, callback, options) {
  var _ref = options !== null && options !== void 0 ? options : {},
    _ref$level = _ref.level,
    level = _ref$level === void 0 ? 0 : _ref$level,
    _ref$childrenKey = _ref.childrenKey,
    childrenKey = _ref$childrenKey === void 0 ? 'children' : _ref$childrenKey,
    parent = _ref.parent,
    _ref$order = _ref.order,
    order = _ref$order === void 0 ? 'lrd' : _ref$order;
  return treeNodes.forEach(function (treeNode, index) {
    if (order == 'dlr') callback(treeNode, {
      level: level,
      index: index,
      parent: parent
    });
    var children = treeNode[childrenKey];
    if (children === null || children === void 0 ? void 0 : children.length) {
      forEach(children, callback, {
        childrenKey: childrenKey,
        level: level + 1,
        parent: treeNode
      });
    }
    if (order == 'lrd') callback(treeNode, {
      level: level,
      index: index,
      parent: parent
    });
  });
};
/**
 * 节点遍历，使用 callback 进行转换
 */
export var map = function map(treeNodes, callback, options) {
  var _ref2 = options !== null && options !== void 0 ? options : {},
    _ref2$level = _ref2.level,
    level = _ref2$level === void 0 ? 0 : _ref2$level,
    _ref2$childrenKey = _ref2.childrenKey,
    childrenKey = _ref2$childrenKey === void 0 ? 'children' : _ref2$childrenKey,
    parent = _ref2.parent;
  return treeNodes.map(function (treeNode, index) {
    var children = treeNode[childrenKey];
    if (children === null || children === void 0 ? void 0 : children.length) {
      var treeNodeWithOutChildren = {};
      Object.keys(treeNode).forEach(function (key) {
        // @ts-ignore
        if (key !== childrenKey) treeNodeWithOutChildren[key] = treeNode[key];
      });
      var convertedTreeNode = callback(treeNodeWithOutChildren, {
        level: level,
        index: index,
        parent: parent
      });
      return _objectSpread(_objectSpread({}, convertedTreeNode), {}, _defineProperty({}, childrenKey, map(children, callback, {
        childrenKey: childrenKey,
        level: level + 1,
        parent: treeNode
      })));
    }
    return callback(treeNode, {
      level: level,
      index: index,
      parent: parent
    });
  });
};
/**
 * 节点过滤
 * @param treeNodes
 * @param callback
 * @param options
 * @returns
 */
export var filter = function filter(treeNodes, callback, options) {
  var _ref3 = options || {},
    _ref3$childrenKey = _ref3.childrenKey,
    childrenKey = _ref3$childrenKey === void 0 ? 'children' : _ref3$childrenKey;
  var filteredTreeNodes = [];
  var internalFilter = function internalFilter(nodes, result) {
    nodes.forEach(function (node) {
      // 遍历子节点
      var children = node[childrenKey];
      if (children === null || children === void 0 ? void 0 : children.length) {
        var filteredChildren = [];
        internalFilter(children, filteredChildren);
        if (!filteredChildren.length) {
          if (callback(node)) {
            result.push(_objectSpread(_objectSpread({}, node), {}, _defineProperty({}, childrenKey, node[childrenKey] === null ? null : undefined)));
          }
          return;
        }
        return result.push(_objectSpread(_objectSpread({}, node), {}, _defineProperty({}, childrenKey, filteredChildren)));
      }
      if (callback(node)) {
        return result.push(_objectSpread(_objectSpread({}, node), {}, _defineProperty({}, childrenKey, node[childrenKey] === null ? null : undefined)));
      }
    });
  };
  internalFilter(treeNodes, filteredTreeNodes);
  return filteredTreeNodes;
};
/**
 * 扁平化成一维数组
 * @param treeNodes
 * @param options
 * @returns
 */
export var toArray = function toArray(treeNodes, options) {
  var _ref4 = options !== null && options !== void 0 ? options : {},
    _ref4$uniqueKey = _ref4.uniqueKey,
    uniqueKey = _ref4$uniqueKey === void 0 ? 'key' : _ref4$uniqueKey,
    _ref4$levelKey = _ref4.levelKey,
    levelKey = _ref4$levelKey === void 0 ? 'level' : _ref4$levelKey,
    _ref4$childrenKey = _ref4.childrenKey,
    childrenKey = _ref4$childrenKey === void 0 ? 'children' : _ref4$childrenKey,
    _ref4$parentKey = _ref4.parentKey,
    parentKey = _ref4$parentKey === void 0 ? 'parentKey' : _ref4$parentKey,
    _ref4$beginingLevel = _ref4.beginingLevel,
    beginingLevel = _ref4$beginingLevel === void 0 ? 1 : _ref4$beginingLevel;
  var result = [];
  forEach(treeNodes, function (treeNode, _ref5) {
    var parent = _ref5.parent,
      levelFromZero = _ref5.level;
    if (!(uniqueKey in treeNode)) {
      logger.fail('please check unique key!');
    }
    // @ts-ignore
    treeNode[levelKey] = levelFromZero + beginingLevel;
    if (levelFromZero !== 0) {
      // @ts-ignore
      treeNode[parentKey] = parent === null || parent === void 0 ? void 0 : parent[uniqueKey];
    }
    result.push(treeNode);
  }, {
    childrenKey: childrenKey,
    order: 'dlr'
  });
  return result;
};
/**
 * 扁平化成映射
 * @param treeNodes
 * @param options
 * @returns
 */
export var toMap = function toMap(treeNodes, options) {
  var _ref6 = options !== null && options !== void 0 ? options : {},
    _ref6$uniqueKey = _ref6.uniqueKey,
    uniqueKey = _ref6$uniqueKey === void 0 ? 'key' : _ref6$uniqueKey,
    _ref6$levelKey = _ref6.levelKey,
    levelKey = _ref6$levelKey === void 0 ? 'level' : _ref6$levelKey,
    _ref6$childrenKey = _ref6.childrenKey,
    childrenKey = _ref6$childrenKey === void 0 ? 'children' : _ref6$childrenKey,
    _ref6$parentKey = _ref6.parentKey,
    parentKey = _ref6$parentKey === void 0 ? 'parentKey' : _ref6$parentKey,
    _ref6$beginingLevel = _ref6.beginingLevel,
    beginingLevel = _ref6$beginingLevel === void 0 ? 1 : _ref6$beginingLevel;
  var result = {};
  forEach(treeNodes, function (treeNode, _ref7) {
    var parent = _ref7.parent,
      levelFromZero = _ref7.level;
    if (!(uniqueKey in treeNode)) {
      logger.fail('please check unique key!');
    }
    if (result[treeNode[uniqueKey]]) {
      logger.fail('some tree-node has same unique key!');
    }
    // @ts-ignore
    treeNode[levelKey] = levelFromZero + beginingLevel;
    if (levelFromZero !== 0) {
      // @ts-ignore
      treeNode[parentKey] = parent === null || parent === void 0 ? void 0 : parent[uniqueKey];
    }
    result[treeNode[uniqueKey]] = treeNode;
  }, {
    childrenKey: childrenKey
  });
  return result;
};
/**
 * 树节点交换顺序
 * @todo 可优化性能
 * @param treeNodes
 * @param options
 * @returns
 */
export var exchange = function exchange(treeNodes, targetNode, sourceNode, options) {
  var _ref8 = options !== null && options !== void 0 ? options : {},
    _ref8$uniqueKey = _ref8.uniqueKey,
    uniqueKey = _ref8$uniqueKey === void 0 ? 'key' : _ref8$uniqueKey,
    _ref8$levelKey = _ref8.levelKey,
    levelKey = _ref8$levelKey === void 0 ? 'level' : _ref8$levelKey,
    _ref8$childrenKey = _ref8.childrenKey,
    childrenKey = _ref8$childrenKey === void 0 ? 'children' : _ref8$childrenKey;
  if (levelKey in targetNode && levelKey in sourceNode && targetNode[levelKey] !== sourceNode[levelKey]) {
    logger.fail('only support nodes that have same parent');
    return;
  }
  var convert = function convert(nodes) {
    return nodes.map(function (node) {
      if (node[uniqueKey] === targetNode[uniqueKey]) {
        return sourceNode;
      } else if (node[uniqueKey] === sourceNode[uniqueKey]) {
        return targetNode;
      } else {
        return node;
      }
    });
  };
  var result = [];
  forEach(treeNodes, function (treeNode, _ref9) {
    var _parent$childrenKey;
    var parent = _ref9.parent;
    var siblings = (_parent$childrenKey = parent === null || parent === void 0 ? void 0 : parent[childrenKey]) !== null && _parent$childrenKey !== void 0 ? _parent$childrenKey : treeNodes;
    var hasTarget = treeNode[uniqueKey] === targetNode[uniqueKey];
    var hasSource = siblings.some(function (node) {
      return node[uniqueKey] === targetNode[uniqueKey];
    });
    if (hasTarget !== hasSource) {
      logger.fail('only support nodes that have same parent');
      return;
    }
    if (hasTarget && hasSource) {
      if (parent) {
        // @ts-ignore
        parent[childrenKey] = convert(parent[childrenKey]);
        result = treeNodes;
      } else {
        result = convert(treeNodes);
      }
    }
  }, {
    childrenKey: childrenKey,
    order: 'dlr'
  });
  return result;
};